package com.anlogic.sdk.tools.exetool;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import org.apache.logging.log4j.Logger;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.console.MessageConsole;
import com.anlogic.sdk.utils.ICommandLauncher;
import com.anlogic.sdk.utils.LogUtils;
import com.anlogic.sdk.utils.UIUtils;
import com.anlogic.sdk.utils.UtilsPlugin;

public class ExeTool {
	private static Logger logger = LogUtils.getLogger(ExeTool.class);

	private MessageConsole console;

	private ICommandLauncher launcher;

	private String toolName;

	private File pwd;

	public ExeTool(String toolName) {
		console = UtilsPlugin.getDefault().getMessageConsole(toolName);
		launcher = UtilsPlugin.getDefault().getLauncher(console);
		this.pwd = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString());
		this.toolName = toolName;
	}

	public void setPrintToConsole(boolean printToConsole) {
		launcher.setPrintToConsole(printToConsole);
	}
	
	public void setRedirectErrToOut(boolean redirectErrToOut) {
		launcher.setRedirectErrToOut(redirectErrToOut);
	}
	
	public String launch(String cmd) {
		if (this.launcher.launch(cmd, this.pwd, null) != 0) {
			logger.error("Unexpected error occurred while executing {}", cmd);
		}
		return this.launcher.flush();
	}
	
	public String launch(IProgressMonitor monitor, String cmd) {
		monitor.beginTask("beginTask...", 1);
        monitor.setTaskName(this.toolName);
		this.launcher.launch(cmd, this.pwd, null);
		monitor.worked(1);
		while (!this.launcher.hasTerminated()) {
			try {
				Thread.sleep(500L);
			} catch (InterruptedException e) {
				logger.error("Unexpected error occurred while executing {} : {}", cmd, e.getMessage());
			}
			if (monitor.isCanceled())
				this.launcher.terminate();
		}
		if (monitor.isCanceled()) {
			monitor.done();
		}
		monitor.done();
		return this.launcher.flush();
	}

	public String asyncLaunch(String cmd) {
		this.launcher.asyncLaunch(cmd, this.pwd, null);
		return this.launcher.flush();
	}
	
	public String asyncLaunch(IProgressMonitor monitor, String cmd) {
		monitor.beginTask("beginTask...", 1);
        monitor.setTaskName(this.toolName);
		this.launcher.asyncLaunch(cmd, this.pwd, null);
		monitor.worked(1);
		while (!this.launcher.hasTerminated()) {
			try {
				Thread.sleep(500L);
			} catch (InterruptedException e) {
				logger.error("Unexpected error occurred while executing {} : {}", cmd, e.getMessage());
			}
			if (monitor.isCanceled())
				this.launcher.terminate();
		}
		if (monitor.isCanceled()) {
			monitor.done();
		}
		monitor.done();
		return this.launcher.flush();
	}

	public void printStdOutMessage(String msg) {
		this.launcher.printStdOutMessage(msg);
	}
	
	public void printStdErrMessage(String msg) {
		this.launcher.printStdErrMessage(msg);
	}

	public void executeJobBackend(String cmd) {
		Job job = new Job(String.format("%s executing...", this.toolName)) {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				asyncLaunch(monitor, cmd);
				return Status.OK_STATUS;
			}
		};
		job.setUser(true);
		job.schedule();
	}
	
	public void executeJob(String cmd) {
		MessageConsole console = UtilsPlugin.getDefault().getMessageConsole(this.toolName);
		ICommandLauncher launcher = UtilsPlugin.getDefault().getLauncher(console);
		
		Job job = new Job(String.format("%s executing...", this.toolName)) {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				launcher.asyncLaunch(cmd, ExeTool.this.pwd, null);
				while (!launcher.hasTerminated()) {
					try {
						Thread.sleep(100L);
					} catch (InterruptedException e) {
						logger.error("Unexpected error occurred while executing {} : {}", cmd, e.getMessage());
					}
					if (monitor.isCanceled())
						launcher.terminate();
				}
				monitor.done();
				return Status.OK_STATUS;
			}
		};
		job.schedule();
	}
	
	public String executeWithProgressBar(String cmd) {
		StringBuffer buffer = new StringBuffer();
		ProgressMonitorDialog progress = new ProgressMonitorDialog(UIUtils.getActiveShell());
		try {
            progress.run(true, true, new IRunnableWithProgress() {
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                	String result = ExeTool.this.launch(monitor, cmd);
                	buffer.append(result);
                }
            });
        } catch (InvocationTargetException | InterruptedException e) {
        	logger.error("Unexpected error occurred while executing {} : {}", cmd, e.getMessage());
        }
		return buffer.toString();
	}
}
